// file: x86/arch/cpu/gate.c
// autor: jiangxinpeng
// time: 2021.1.1
// copyright: (C) 2020-2050 by jiangxinpeng,All right are reserved.

#include <arch/gate.h>
#include <arch/segment.h>
#include <arch/apic.h>
#include <arch/interrupt.h>
#include <arch/mp.h>
#include <lib/assert.h>
#include <arch/memory.h>
#include <lib/type.h>
#include <arch/x86.h>

#define INT_GATE_ATTR ((uint8_t)(((uint8_t)DPL_3 << 5) | ((uint8_t)SEG_TYPE_INTGATE) | (1 << 7)))

volatile gate_t *idt = NULL;

extern void AsmTest();

#pragma GCC optimize("O0")

// init sys gate descript
void GateDescriptInit()
{ // init interrupt expection info
    InterruptInit();
    // init interrupt gate
    InterruptGateInit();
}

void InterruptGateInit()
{
    idt = page_enable ? (gate_t *)IDT_VBASE : IDT_BASE;

    // init all int gate descript
    for (int i = 0; i < INT_MAX; i++)
    {
        *(idt + i) = MakeGateDescript(0, 0, 0);
    }
    
    // interrupt gate install
    idt[0] = MakeGateDescript(SEG_SEL_KERNEL_CODE, (uint32_t)ExceptionEntry0x00, INT_GATE_ATTR);
    idt[1] = MakeGateDescript(SEG_SEL_KERNEL_CODE, (uint32_t)ExceptionEntry0x01, INT_GATE_ATTR);
    idt[2] = MakeGateDescript(SEG_SEL_KERNEL_CODE, (uint32_t)ExceptionEntry0x02, INT_GATE_ATTR);
    idt[3] = MakeGateDescript(SEG_SEL_KERNEL_CODE, (uint32_t)ExceptionEntry0x03, INT_GATE_ATTR);
    idt[4] = MakeGateDescript(SEG_SEL_KERNEL_CODE, (uint32_t)ExceptionEntry0x04, INT_GATE_ATTR);
    idt[5] = MakeGateDescript(SEG_SEL_KERNEL_CODE, (uint32_t)ExceptionEntry0x05, INT_GATE_ATTR);
    idt[6] = MakeGateDescript(SEG_SEL_KERNEL_CODE, (uint32_t)ExceptionEntry0x06, INT_GATE_ATTR);
    idt[7] = MakeGateDescript(SEG_SEL_KERNEL_CODE, (uint32_t)ExceptionEntry0x07, INT_GATE_ATTR);
    idt[8] = MakeGateDescript(SEG_SEL_KERNEL_CODE, (uint32_t)ExceptionEntry0x08, INT_GATE_ATTR);
    idt[9] = MakeGateDescript(SEG_SEL_KERNEL_CODE, (uint32_t)ExceptionEntry0x09, INT_GATE_ATTR);
    idt[10] = MakeGateDescript(SEG_SEL_KERNEL_CODE, (uint32_t)ExceptionEntry0x0a, INT_GATE_ATTR);
    idt[11] = MakeGateDescript(SEG_SEL_KERNEL_CODE, (uint32_t)ExceptionEntry0x0b, INT_GATE_ATTR);
    idt[12] = MakeGateDescript(SEG_SEL_KERNEL_CODE, (uint32_t)ExceptionEntry0x0c, INT_GATE_ATTR);
    idt[13] = MakeGateDescript(SEG_SEL_KERNEL_CODE, (uint32_t)ExceptionEntry0x0d, INT_GATE_ATTR);
    idt[14] = MakeGateDescript(SEG_SEL_KERNEL_CODE, (uint32_t)ExceptionEntry0x0e, INT_GATE_ATTR);
    idt[15] = MakeGateDescript(SEG_SEL_KERNEL_CODE, (uint32_t)ExceptionEntry0x0f, INT_GATE_ATTR);
    idt[16] = MakeGateDescript(SEG_SEL_KERNEL_CODE, (uint32_t)ExceptionEntry0x10, INT_GATE_ATTR);
    idt[17] = MakeGateDescript(SEG_SEL_KERNEL_CODE, (uint32_t)ExceptionEntry0x11, INT_GATE_ATTR);
    idt[18] = MakeGateDescript(SEG_SEL_KERNEL_CODE, (uint32_t)ExceptionEntry0x12, INT_GATE_ATTR);
    idt[19] = MakeGateDescript(SEG_SEL_KERNEL_CODE, (uint32_t)ExceptionEntry0x13, INT_GATE_ATTR);
    idt[20] = MakeGateDescript(SEG_SEL_KERNEL_CODE, (uint32_t)ExceptionEntry0x14, INT_GATE_ATTR);
    idt[21] = MakeGateDescript(SEG_SEL_KERNEL_CODE, (uint32_t)ExceptionEntry0x15, INT_GATE_ATTR);
    idt[22] = MakeGateDescript(SEG_SEL_KERNEL_CODE, (uint32_t)ExceptionEntry0x16, INT_GATE_ATTR);
    idt[23] = MakeGateDescript(SEG_SEL_KERNEL_CODE, (uint32_t)ExceptionEntry0x17, INT_GATE_ATTR);
    idt[23] = MakeGateDescript(SEG_SEL_KERNEL_CODE, (uint32_t)ExceptionEntry0x17, INT_GATE_ATTR);
    idt[24] = MakeGateDescript(SEG_SEL_KERNEL_CODE, (uint32_t)ExceptionEntry0x18, INT_GATE_ATTR);
    idt[25] = MakeGateDescript(SEG_SEL_KERNEL_CODE, (uint32_t)ExceptionEntry0x19, INT_GATE_ATTR);
    idt[26] = MakeGateDescript(SEG_SEL_KERNEL_CODE, (uint32_t)ExceptionEntry0x1a, INT_GATE_ATTR);
    idt[27] = MakeGateDescript(SEG_SEL_KERNEL_CODE, (uint32_t)ExceptionEntry0x1b, INT_GATE_ATTR);
    idt[28] = MakeGateDescript(SEG_SEL_KERNEL_CODE, (uint32_t)ExceptionEntry0x1c, INT_GATE_ATTR);
    idt[29] = MakeGateDescript(SEG_SEL_KERNEL_CODE, (uint32_t)ExceptionEntry0x1d, INT_GATE_ATTR);
    idt[30] = MakeGateDescript(SEG_SEL_KERNEL_CODE, (uint32_t)ExceptionEntry0x1e, INT_GATE_ATTR);
    idt[31] = MakeGateDescript(SEG_SEL_KERNEL_CODE, (uint32_t)ExceptionEntry0x1f, INT_GATE_ATTR);
    // hardware irq install
    idt[32] = MakeGateDescript(SEG_SEL_KERNEL_CODE, (uint32_t)IrqEntry0x20, INT_GATE_ATTR);
    idt[33] = MakeGateDescript(SEG_SEL_KERNEL_CODE, (uint32_t)IrqEntry0x21, INT_GATE_ATTR);
    idt[34] = MakeGateDescript(SEG_SEL_KERNEL_CODE, (uint32_t)IrqEntry0x22, INT_GATE_ATTR);
    idt[35] = MakeGateDescript(SEG_SEL_KERNEL_CODE, (uint32_t)IrqEntry0x23, INT_GATE_ATTR);
    idt[36] = MakeGateDescript(SEG_SEL_KERNEL_CODE, (uint32_t)IrqEntry0x24, INT_GATE_ATTR);
    idt[37] = MakeGateDescript(SEG_SEL_KERNEL_CODE, (uint32_t)IrqEntry0x25, INT_GATE_ATTR);
    idt[38] = MakeGateDescript(SEG_SEL_KERNEL_CODE, (uint32_t)IrqEntry0x26, INT_GATE_ATTR);
    idt[39] = MakeGateDescript(SEG_SEL_KERNEL_CODE, (uint32_t)IrqEntry0x27, INT_GATE_ATTR);
    idt[40] = MakeGateDescript(SEG_SEL_KERNEL_CODE, (uint32_t)IrqEntry0x28, INT_GATE_ATTR);
    idt[41] = MakeGateDescript(SEG_SEL_KERNEL_CODE, (uint32_t)IrqEntry0x29, INT_GATE_ATTR);
    idt[42] = MakeGateDescript(SEG_SEL_KERNEL_CODE, (uint32_t)IrqEntry0x2a, INT_GATE_ATTR);
    idt[43] = MakeGateDescript(SEG_SEL_KERNEL_CODE, (uint32_t)IrqEntry0x2b, INT_GATE_ATTR);
    idt[44] = MakeGateDescript(SEG_SEL_KERNEL_CODE, (uint32_t)IrqEntry0x2c, INT_GATE_ATTR);
    idt[45] = MakeGateDescript(SEG_SEL_KERNEL_CODE, (uint32_t)IrqEntry0x2d, INT_GATE_ATTR);
    idt[46] = MakeGateDescript(SEG_SEL_KERNEL_CODE, (uint32_t)IrqEntry0x2e, INT_GATE_ATTR);
    idt[47] = MakeGateDescript(SEG_SEL_KERNEL_CODE, (uint32_t)IrqEntry0x2f, INT_GATE_ATTR);
    // syscall
    idt[SYSCALL_NUM] = MakeGateDescript(SEG_SEL_KERNEL_CODE, (uint32_t)SysCallHandler, INT_GATE_ATTR);

#ifdef ENABLE_SMP
    // APIC timer
    idt[LOCAL_TIMER_VECTOR] = MakeGateDescript(SEG_SEL_KERNEL_CODE, (uint32_t)APICTimerHandler, INT_GATE_ATTR);
    idt[LOCAL_ERROR_VECTOR] = MakeGateDescript(SEG_SEL_KERNEL_CODE, (uint32_t)APICErrHandler, INT_GATE_ATTR);
#endif

    // set Idtr register
    page_enable ? LoadIDTR(IDT_LIMIT, IDT_VBASE) : LoadIDTR(IDT_LIMIT, IDT_BASE);
    KPrint("[gate] gate descript init done.\n");
}

gate_t MakeGateDescript(uint16_t sel, uint32_t offset, uint8_t attr)
{
    gate_t des;
    des.sel = sel;
    des.attr = attr;
    des.datacount = 0;
    des.off_high = (offset >> 16) & 0xffff;
    des.off_low = offset & 0xffff;

    return des;
}

void SetGateDescript(uint8_t vec, void *handler)
{
    assert(vec < 0xff);
    wmb();
    idt[vec] = MakeGateDescript(SEG_SEL_KERNEL_CODE, (uint32_t)handler, INT_GATE_ATTR);
}